<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>通讯组件管理</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 搜索筛选 -->
    <el-form :inline="true" :model="searchFrom" class="search-form">
      <el-form-item>
        <el-button
          size="small"
          type="primary"
          icon="el-icon-plus"
          @click="handleEdit()"
          >添加</el-button
        >
      </el-form-item>
    </el-form>
    <el-row :gutter="40">
      <el-col
        :span="6"
        :sm="6"
        :xs="24"
        v-for="com in listData"
        :key="com.id"
        style="margin: 10px 0"
      >
        <el-card>
          <div slot="header" class="clearfix">
            <b>{{ com.name }}</b>
            <div style="float: right">
              <el-popconfirm
                title="确认要删除吗？"
                @confirm="handleDelete(com)"
              >
                <el-button
                  slot="reference"
                  size="mini"
                  icon="el-icon-delete"
                  plain
                ></el-button>
              </el-popconfirm>
            </div>
          </div>
          <el-descriptions
            :column="1"
            size="medium"
            :labelStyle="{ fontWeight: 'bold' }"
          >
            <el-descriptions-item label="通讯协议">{{
              com.protocol
            }}</el-descriptions-item>
            <el-descriptions-item label="转换器">{{
              com.converterName
            }}</el-descriptions-item>
            <el-descriptions-item
              label="jar包"
              :labelStyle="{ fontWeight: 'bold', width: '50px' }"
              >{{ com.jarFile }}</el-descriptions-item
            >
            <el-descriptions-item label="状态">
              <el-switch
                v-model="com.flag"
                active-text="运行中"
                inactive-text="已停止"
                @change="stateChange(com)"
              >
              </el-switch>
            </el-descriptions-item>
            <el-descriptions-item label="操作">
              <el-button
                @click="handleEdit(com)"
                size="mini"
                icon="el-icon-edit"
                plain
              ></el-button>
              <el-button
                @click="handleEditScript(com)"
                class="mg-left-10"
                size="mini"
                >编写脚本</el-button
              >
            </el-descriptions-item>
          </el-descriptions>
        </el-card>
      </el-col>
    </el-row>

    <!-- 编辑界面 -->
    <el-dialog
      :title="title"
      :visible.sync="editFormVisible"
      width="600px"
      @click="closeDialog"
    >
      <el-form
        label-width="120px"
        :model="editForm"
        :rules="rules"
        ref="editForm"
      >
        <el-form-item label="组件名称" prop="name">
          <el-input
            size="small"
            v-model="editForm.name"
            auto-complete="off"
            placeholder="请输入组件名称"
          ></el-input>
        </el-form-item>
        <el-form-item label="组件类型" prop="type">
          <el-radio-group v-model="editForm.type">
            <el-radio label="device">设备组件</el-radio>
            <el-radio label="biz">业务组件</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item
          v-if="editForm.type == 'device'"
          label="转换器"
          prop="converter"
        >
          <el-select v-model="editForm.converter" placeholder="请选择转换器">
            <el-option
              v-for="con in converters"
              :key="con.id"
              :label="con.name"
              :value="con.id"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="通讯协议" prop="protocol">
          <el-select v-model="editForm.protocol" placeholder="请选择通讯协议">
            <el-option label="MQTT" value="mqtt"> </el-option>
            <el-option label="HTTP" value="http"> </el-option>
          </el-select>
        </el-form-item>
        <el-form-item
          v-if="editForm.protocol == 'mqtt'"
          label="配置"
          prop="config"
        >
          <el-form
            style="
              border: 1px solid #ddd;
              padding: 10px 10px;
              box-sizing: border-box;
              border-radius: 3px;
            "
            label-width="80px"
            :model="mqttConfigForm"
            :rules="mqttConfigRule"
            ref="mqttConfigForm"
          >
            <el-form-item label="端口" prop="port">
              <el-input
                style="width: 250px"
                size="small"
                v-model="mqttConfigForm.port"
                auto-complete="off"
                placeholder="请输入端口"
              ></el-input>
            </el-form-item>
            <el-form-item label="模式" prop="type">
              <el-radio v-model="mqttConfigForm.type" label="server"
                >服务端模式</el-radio
              >
              <el-radio v-model="mqttConfigForm.type" label="client"
                >客户端模式</el-radio
              >
              <div>
                <el-tag v-if="mqttConfigForm.type == 'server'" type="info">
                  设备直连通讯组件，收到设备消息直接进行处理
                </el-tag>
                <el-tag v-if="mqttConfigForm.type == 'client'" type="info">
                  设备连接其它broker，通讯组件从broker获取设备消息处理
                </el-tag>
              </div>
            </el-form-item>
            <el-form-item
              v-if="mqttConfigForm.type == 'client'"
              label="认证端口"
              prop="authPort"
            >
              <el-input
                style="width: 250px"
                size="small"
                v-model="mqttConfigForm.authPort"
                auto-complete="off"
                placeholder="请输入认证端口"
              ></el-input>
            </el-form-item>
            <el-form-item
              v-if="mqttConfigForm.type == 'client'"
              label="地址"
              prop="broker"
            >
              <el-input
                style="width: 250px"
                size="small"
                v-model="mqttConfigForm.broker"
                auto-complete="off"
                placeholder="请输入broker地址"
              ></el-input>
            </el-form-item>
            <el-form-item
              v-if="mqttConfigForm.type == 'client'"
              label="clientId"
              prop="clientId"
            >
              <el-input
                style="width: 250px"
                size="small"
                v-model="mqttConfigForm.clientId"
                auto-complete="off"
                placeholder="请输入clientId"
              ></el-input>
            </el-form-item>
            <el-form-item
              v-if="mqttConfigForm.type == 'client'"
              label="用户名"
              prop="username"
            >
              <el-input
                style="width: 250px"
                size="small"
                v-model="mqttConfigForm.username"
                auto-complete="off"
                placeholder="请输入用户名"
              ></el-input>
            </el-form-item>
            <el-form-item
              v-if="mqttConfigForm.type == 'client'"
              label="密码"
              prop="password"
            >
              <el-input
                style="width: 250px"
                size="small"
                v-model="mqttConfigForm.password"
                auto-complete="off"
                placeholder="请输入密码"
              ></el-input>
            </el-form-item>
          </el-form>
        </el-form-item>
        <el-form-item
          v-if="editForm.protocol == 'http'"
          label="配置"
          prop="config"
        >
          <el-form
            style="
              border: 1px solid #ddd;
              padding: 10px 10px;
              box-sizing: border-box;
              border-radius: 3px;
            "
            label-width="60px"
            :model="httpConfigForm"
            :rules="httpConfigRule"
            ref="httpConfigForm"
          >
            <el-form-item label="端口" prop="port">
              <el-input
                style="width: 250px"
                size="small"
                v-model="httpConfigForm.port"
                auto-complete="off"
                placeholder="请输入端口"
              ></el-input>
            </el-form-item>
          </el-form>
        </el-form-item>
        <el-form-item label="jar包" prop="jarFile">
          <div v-if="editForm.jarFile">
            <el-tag
              size="medium"
              type="info"
              closable
              @close="deleteJarFile(editForm)"
              >{{ editForm.jarFile }}</el-tag
            >
          </div>
          <el-upload
            v-else
            ref="jarUpload"
            :headers="headers"
            :data="editForm"
            :action="uploadAction"
            :on-success="uploadSUccess"
            :limit="1"
            :auto-upload="false"
          >
            <el-button size="small" type="primary">点击上传</el-button>
            <div slot="tip" class="el-upload__tip">
              只能上传jar文件，且不超过10M
            </div>
          </el-upload>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button size="small" @click="closeDialog">取消</el-button>
        <el-button
          size="small"
          type="primary"
          :loading="$store.state.loading"
          class="title"
          @click="submitEditForm('editForm')"
          >保存</el-button
        >
      </div>
    </el-dialog>

    <el-dialog
      :title="isFullScreen ? '' : '通讯脚本编写'"
      :visible.sync="editScriptVisible"
      :show-close="false"
      width="80%"
      custom-class="code-dialog"
      :fullscreen="isFullScreen"
      @click="closeDialog"
    >
      <div v-if="isFullScreen">
        通讯脚本：<el-button @click="fullScreen(false)" size="mini"
          >退出全屏</el-button
        >
        <div>new (function () {</div>
        <ScriptEditor :code="editScript"></ScriptEditor>
        <div>})()</div>
      </div>

      <el-row v-else>
        <el-col :span="12">
          通讯脚本：<el-button @click="fullScreen(true)" size="mini"
            >全屏</el-button
          >
          <div>new (function () {</div>
          <div style="height: 320px; overflow: auto">
            <ScriptEditor :code="editScript"></ScriptEditor>
          </div>
          <div>})()</div>
        </el-col>
        <el-col :span="1">&nbsp;</el-col>
        <el-col :span="11">
          测试数据：
          <div style="height: 150px; overflow: auto">
            <JsonEditor :code="testDataScript"></JsonEditor>
          </div>
          <el-row style="padding: 5px 5px">
            <el-col :span="12"> 测试结果： </el-col>
            <el-col :span="6">
              <el-button size="mini" type="primary" @click="execTest"
                >测试</el-button
              >
            </el-col>
          </el-row>
          <div>
            <el-input
              type="textarea"
              v-model="testResult"
              :readonly="true"
              :rows="7"
            >
            </el-input>
          </div>
        </el-col>
      </el-row>

      <div slot="footer" class="dialog-footer">
        <el-button size="small" @click="closeDialog">取消</el-button>
        <el-button
          size="small"
          type="primary"
          :loading="$store.state.loading"
          @click="submitSaveScript"
          >保存</el-button
        >
      </div>
    </el-dialog>
  </div>
</template>

<script>
import {
  ComponentList,
  ConverterList,
  ComponentAdd,
  ComponentSave,
  ComponentDelete,
  ComponentScriptSave,
  ComponentScriptGet,
  ComponentStateChange,
} from "@/api/protocolApi";
import ScriptEditor from "@/components/ScriptEditor.vue";
import JsonEditor from "./JsonEditor.vue";
import Vue from "vue";

export default {
  data() {
    return {
      loading: false,
      editFormVisible: false,
      editScriptVisible: false,
      isAdd: true,
      title: "",
      uploadAction: process.env.VUE_APP_API_BASE_PATH + "/protocol/uploadJar",
      headers: { token: `${Vue.prototype.accessToken}` },
      editForm: {
        id: "",
        name: "",
        converter: "",
        protocol: "",
        jarFile: "",
        config: "",
        type: "device",
      },
      rules: {
        name: [{ required: true, message: "请输入组件名称", trigger: "blur" }],
        protocol: [{ required: true, message: "请选择协议", trigger: "blur" }],
        converter: [
          { required: true, message: "请选择转换器", trigger: "blur" },
        ],
      },
      mqttConfigForm: {
        port: 1883,
        ssl: false,
        type: "server",
        subscribeTopics: [
          "/sys/+/+/s/#",
          "/sys/client/connected",
          "/sys/client/disconnected",
          "/sys/session/subscribed",
          "/sys/session/unsubscribed",
        ],
      },
      mqttConfigRule: {
        port: [{ required: true, message: "请输入端口号", trigger: "blur" }],
      },
      httpConfigForm: {
        port: 0,
      },
      httpConfigRule: {
        port: [{ required: true, message: "请输入端口号", trigger: "blur" }],
      },
      searchFrom: {
        page: 1,
        size: 10,
        total: 0,
      },
      listData: [],
      converters: [],
      editScript: {},
      testDataScript: {
        script: "{}",
      },
      testResult: "",
      isFullScreen: false,
    };
  },
  components: {
    ScriptEditor,
    JsonEditor,
  },
  created() {
    this.getdata(this.searchFrom);
  },
  methods: {
    getdata(parameter) {
      let load = this.$loading();
      ComponentList(parameter).then((res) => {
        res.data.forEach((d) => {
          d.flag = d.state == "running";
        });
        let components = res.data;
        this.searchFrom.total = res.total;

        ConverterList({ page: 1, size: 100 }).then((res) => {
          this.converters = res.data;
          components.forEach((cp) => {
            let idx = this.converters.findIndex((c) => {
              return c.id == cp.converter;
            });
            if (idx >= 0) {
              cp.converterName = this.converters[idx].name;
            }
          });

          this.listData = components;
          load.close();
        });
      });
    },
    search() {
      this.getdata(this.searchFrom);
    },
    onPagePaging() {
      this.search();
    },
    handleEdit(row) {
      this.editFormVisible = true;
      if (row != undefined && row != "undefined") {
        this.isAdd = false;
        this.title = "修改通讯组件";
        this.editForm.id = row.id;
        this.editForm.converter = row.converter;
        this.editForm.name = row.name;
        this.editForm.protocol = row.protocol;
        this.editForm.jarFile = row.jarFile;
        this.editForm.config = row.config;
        this.editForm.type = row.type;
        if (row.config) {
          if (row.protocol == "mqtt") {
            this.mqttConfigForm = JSON.parse(row.config);
          } else if (row.protocol == "http") {
            this.httpConfigForm = JSON.parse(row.config);
          }
        }
      } else {
        this.isAdd = true;
        this.title = "添加通讯组件";
        this.editForm.id = "";
        this.editForm.converter = "";
        this.editForm.name = "";
        this.editForm.protocol = "mqtt";
        this.editForm.jarFile = "";
        this.editForm.config = "";
        this.editForm.type = "device";
      }
    },
    handleEditScript(row) {
      let load = this.$loading();
      ComponentScriptGet(row.id).then((res) => {
        this.editScriptVisible = true;
        this.editScript.id = row.id;
        if (!res) {
          res = `this.onReceive = function (head,type,payload) {
  return null;
};`;
        }
        this.editScript = { id: row.id, script: res };
        this.testDataScript.script =
          localStorage.getItem("testDataScript_" + row.id) || "{}";
        load.close();
      });
    },
    handleDelete(row) {
      ComponentDelete(row.id).then(() => {
        this.$notify({
          title: "成功",
          message: "删除成功",
          type: "success",
        });
        this.search();
      });
    },
    stateChange(com) {
      ComponentStateChange({
        id: com.id,
        state: com.flag ? "running" : "stopped",
      }).then(
        () => {
          this.$notify({
            title: "成功",
            message: (com.flag ? "启动" : "停止") + "组件成功",
            type: "success",
          });
        },
        (res) => {
          this.$notify({
            title: "失败",
            message: (com.flag ? "启动" : "停止") + "组件失败：" + res,
            type: "error",
          });
        }
      );
    },
    uploadSUccess(response, file) {
      console.log(response, file);
      this.editForm.id = response;
      this.editForm.jarFile = file.name;
      if (this.isAdd) {
        let protocol = this.editForm.protocol;
        if (protocol == "http") {
          this.editForm.config = JSON.stringify(this.httpConfigForm);
        } else if (protocol == "mqtt") {
          this.editForm.config = JSON.stringify(this.mqttConfigForm);
        }

        ComponentAdd(this.editForm).then(() => {
          this.$notify({
            title: "成功",
            message: "添加成功",
            type: "success",
          });
          this.editFormVisible = false;
          this.search();
        });
      } else {
        this.componentEditSave();
      }
    },
    componentEditSave() {
      let protocol = this.editForm.protocol;
      if (protocol == "http") {
        this.editForm.config = JSON.stringify(this.httpConfigForm);
      } else if (protocol == "mqtt") {
        this.editForm.config = JSON.stringify(this.mqttConfigForm);
      }

      ComponentSave(this.editForm).then(() => {
        this.$notify({
          title: "成功",
          message: "修改成功",
          type: "success",
        });
        this.editFormVisible = false;
        this.search();
      });
    },
    deleteJarFile(form) {
      form.jarFile = "";
    },
    submitEditForm(form) {
      this.$refs[form].validate((valid) => {
        if (valid) {
          let uploader = this.$refs["jarUpload"];
          //选择了上传文件
          if (uploader && uploader.uploadFiles.length > 0) {
            uploader.submit();
          } else if (!this.editForm.jarFile) {
            //既没选择文件又没上传过
            this.$notify({
              title: "失败",
              message: "请先上传jar包",
              type: "error",
            });
          } else {
            this.componentEditSave();
          }
        }
      });
    },
    submitSaveScript() {
      ComponentScriptSave(this.editScript).then(() => {
        this.$notify({
          title: "成功",
          message: "修改成功",
          type: "success",
        });
        this.editScriptVisible = false;
        this.search();
      });
    },
    closeDialog() {
      this.editFormVisible = false;
      this.editScriptVisible = false;
    },
    execTest() {
      try {
        localStorage.setItem(
          "testDataScript_" + this.editScript.id,
          this.testDataScript.script || '{head:"",type:"",payload:""}'
        );

        var script = "new (function (){" + this.editScript.script + "})()";
        var coder = eval(script);
        var testData = eval(
          "(function(){return " + this.testDataScript.script + "})()"
        );
        this.testResult = JSON.stringify(
          coder.onReceive(testData.head, testData.type, testData.payload)
        );
      } catch (err) {
        this.testResult = err;
      }
    },
    fullScreen(flag) {
      this.isFullScreen = flag;
    },
  },
};
</script>

<style>
.CodeMirror {
  height: 100%;
}

.code-dialog.is-fullscreen .el-dialog__header {
  display: none !important;
}

.code-dialog.is-fullscreen .el-dialog__body {
  padding: 5px 5px !important;
}
</style>